package com.zatech.cgnci.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zatech.cgnci.project.base.context.UserContext;
import com.zatech.cgnci.project.base.enums.BillStatusEnum;
import com.zatech.cgnci.project.base.enums.BillTypeEnum;
import com.zatech.cgnci.project.base.enums.BusinessStatusEnum;
import com.zatech.cgnci.project.base.enums.ResponseCodeEnum;
import com.zatech.cgnci.project.base.exception.GlobalException;
import com.zatech.cgnci.project.base.utils.ConvertUtils;
import com.zatech.cgnci.project.base.utils.DateUtils;
import com.zatech.cgnci.project.base.utils.VerifyUtils;
import com.zatech.cgnci.project.dto.*;
import com.zatech.cgnci.project.entity.*;
import com.zatech.cgnci.project.mapper.*;
import com.zatech.cgnci.project.service.*;
import com.zatech.cgnci.project.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 合约账单信息 服务实现类
 * </p>
 *
 * @author Generator
 * @since 2024-12-30
 */
@Service
public class CgnciContractInvoiceServiceImpl extends ServiceImpl<CgnciContractInvoiceMapper, CgnciContractInvoiceDO> implements CgnciContractInvoiceService {

    @Resource
    private CgnciContractBillDetailsMapper detailsMapper;
    @Autowired
    private CgnciReceiptPaymentBillsMapper billsMapper;
    @Autowired
    private CgnciBusinessInsuranceMapper businessInsuranceMapper;
    @Autowired
    private CgnciReinsuranceInfoMapper cgnciReinsuranceInfoMapper;
    @Autowired
    private CgnciReinsuranceInfoService reinsuranceInfoService;
    @Resource
    private CgnciReinsuranceRiskService cgnciReinsuranceRiskService;
    @Resource
    private CgnciReinsuranceRiskLayerService cgnciReinsuranceRiskLayerService;
    @Resource
    CgnciReinsurerService reinsurerService;
    @Autowired
    private CgnciReinsuranceRiskInsuredService cgnciReinsuranceRiskInsuredService;

    @Override
    public IPage<ContractInvoiceVO> pageQuery(ContractInvoiceQueryDTO queryDTO) {
        return this.baseMapper.pageBusinessInsurance(queryDTO.toPage(), queryDTO);
    }

    /**
     * 合约账单新增接口
     * @param addDTO
     */
    @Override
    public void addContractInvoice(ContractInvoiceAddDTO addDTO) {
        UserEntity user = UserContext.getUser();
        addDTO.setCreateUser(user.getNameAndCode());
        StringBuilder invoiceNumber = new StringBuilder();
        if(addDTO.getDirection().equals("1")){
            invoiceNumber.append("SK");
        }else if(addDTO.getDirection().equals("2")){
            invoiceNumber.append("FK");
        }

        invoiceNumber.append(DateUtils.dateElaborate());
        // 获取当前日期的开始时间和结束时间
        LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
        LocalDateTime endOfDay = LocalDate.now().atTime(LocalTime.MAX);
        int count = this.baseMapper.selectCount(
                new LambdaQueryWrapper<CgnciContractInvoiceDO>()
                        .between(CgnciContractInvoiceDO::getCreateTime,
                                Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()),
                                Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()))
        );
        invoiceNumber.append(String.format("%04d", count));
        //合约账单
        CgnciContractInvoiceDO cgnciContractInvoiceDO = CgnciContractInvoiceDO.builder()
                .contractNumber(addDTO.getContractNumber())
                .contractName(addDTO.getContractName())
                .contractType(addDTO.getContractType())
                .contractDeadline(addDTO.getContractDeadline())
                .cedingCompany(addDTO.getCedingCompany())
                .receiver(addDTO.getReceiver())
                .invoiceNumber(invoiceNumber.toString())
                .projectName(addDTO.getProjectName())
                .currency(addDTO.getCurrency())
                .fxRate(addDTO.getFxRate())
                .direction(addDTO.getDirection())
                .collectAmount(addDTO.getCollectAmount())
                .billRecipient(addDTO.getBillRecipient())
                .billingCycle(addDTO.getBillingCycle())
                .status(BillStatusEnum.UNSETTLED.getCode())
                .dueDate(addDTO.getDueDate())
                .createUser(addDTO.getCreateUser())
                .createTime(new Date())
                .build();
        this.baseMapper.insert(cgnciContractInvoiceDO);
        CgnciReceiptPaymentBillsDO paymentBillsDO = ConvertUtils.convert(addDTO,CgnciReceiptPaymentBillsDO.class);
        paymentBillsDO.setAmount(addDTO.getCollectAmount());
        paymentBillsDO.setInvoiceNumber(invoiceNumber.toString());
        paymentBillsDO.setBillType(BillTypeEnum.CONTRACT_INVOICE.getCode());
        paymentBillsDO.setStatus(BillStatusEnum.UNSETTLED.getCode());
        //插入收付费账单表
        billsMapper.insert(paymentBillsDO);
        for (ContractBillDetailsAddDTO detailsAddDTO:addDTO.getDetailsAddDTOS()){
            //账单明细
            CgnciContractBillDetailsDO cgnciContractBillDetailsDO = CgnciContractBillDetailsDO.builder()
                    .invoiceNumber(invoiceNumber.toString())
                    .feeType(detailsAddDTO.getFeeType())
                    .paymentType(detailsAddDTO.getPaymentType())
                    .amount(detailsAddDTO.getAmount())
                    .createUser(addDTO.getCreateUser())
                    .createTime(new Date())
                    .build();
            detailsMapper.insert(cgnciContractBillDetailsDO);
        }
    }

    @Override
    public ContractInvoiceDetailsVO getDetails(Long id, String invoiceNumber) {
        CgnciContractInvoiceDO contractInvoiceDO =this.baseMapper.selectById(id);
        ContractInvoiceDetailsVO invoiceDetailsVO = ConvertUtils.convert(contractInvoiceDO,ContractInvoiceDetailsVO.class);
        CgnciContractBillDetailsDO queryDO = CgnciContractBillDetailsDO.builder()
                .invoiceNumber(invoiceNumber).build();
        List<CgnciContractBillDetailsDO> detailsDOList = detailsMapper.selectList(new LambdaUpdateWrapper<CgnciContractBillDetailsDO>()
                        .eq(CgnciContractBillDetailsDO::getInvoiceNumber, queryDO.getInvoiceNumber()));
        List<ContractBillDetailsAddDTO> detailsAddDTOS = new ArrayList<>();
        for(CgnciContractBillDetailsDO detailsDO:detailsDOList){
            ContractBillDetailsAddDTO detailsAddDTO = new ContractBillDetailsAddDTO();
            detailsAddDTO.setAmount(detailsDO.getAmount());
            detailsAddDTO.setPaymentType(detailsDO.getPaymentType());
            detailsAddDTO.setFeeType(detailsDO.getFeeType());
            detailsAddDTOS.add(detailsAddDTO);
        }
        invoiceDetailsVO.setDetailsAddDTOS(detailsAddDTOS);
        return invoiceDetailsVO;
    }

    @Override
    public void updateContractInvoice(ContractInvoiceUpdateDTO updateDTO) {
        UserEntity user = UserContext.getUser();
        Integer count =  billsMapper.selectCount(new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                .eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber,updateDTO.getInvoiceNumber())
                .eq(CgnciReceiptPaymentBillsDO::getStatus,BillStatusEnum.UNSETTLED.getCode()));
        if(count==0){
            throw new GlobalException(ResponseCodeEnum.HTTP_REQUEST_SERVICE_ERROR, "收付费平台已关联，不允许更新");
        }
        //合约账单
        CgnciContractInvoiceDO cgnciContractInvoiceDO = CgnciContractInvoiceDO.builder()
                .id(updateDTO.getId())
                .contractNumber(updateDTO.getContractNumber())
                .contractName(updateDTO.getContractName())
                .contractType(updateDTO.getContractType())
                .contractDeadline(updateDTO.getContractDeadline())
                .cedingCompany(updateDTO.getCedingCompany())
                .receiver(updateDTO.getReceiver())
                .projectName(updateDTO.getProjectName())
                .currency(updateDTO.getCurrency())
                .fxRate(updateDTO.getFxRate())
                .direction(updateDTO.getDirection())
                .collectAmount(updateDTO.getCollectAmount())
                .billRecipient(updateDTO.getBillRecipient())
                .billingCycle(updateDTO.getBillingCycle())
                .dueDate(updateDTO.getDueDate())
                .createUser(updateDTO.getUpdateUser())
                .updateTime(new Date())
                .build();
        this.baseMapper.updateById(cgnciContractInvoiceDO);
        CgnciReceiptPaymentBillsDO paymentBillsDO = ConvertUtils.convert(updateDTO,CgnciReceiptPaymentBillsDO.class);
        paymentBillsDO.setAmount(updateDTO.getCollectAmount());
        paymentBillsDO.setId(null);
        //更新收付费账单表
        billsMapper.update(paymentBillsDO,new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>().eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber,updateDTO.getInvoiceNumber()));
        detailsMapper.delete( new LambdaQueryWrapper<CgnciContractBillDetailsDO>().eq(CgnciContractBillDetailsDO::getInvoiceNumber,updateDTO.getInvoiceNumber()));
        for (ContractBillDetailsAddDTO detailsAddDTO:updateDTO.getDetailsAddDTOS()){
            //账单明细
            CgnciContractBillDetailsDO updateDO = CgnciContractBillDetailsDO.builder()
                    .invoiceNumber(updateDTO.getInvoiceNumber())
                    .feeType(detailsAddDTO.getFeeType())
                    .paymentType(detailsAddDTO.getPaymentType())
                    .amount(detailsAddDTO.getAmount())
                    .createUser(user.getNameAndCode())
                    .updateUser(updateDTO.getUpdateUser())
                    .updateTime(new Date())
                    .build();
            detailsMapper.insert(updateDO);
        }
    }

    @Override
    public void updateUpm(ContractInvoiceUpmUpDTO updateDTO) {
        //合约账单
        CgnciContractInvoiceDO cgnciContractInvoiceDO = CgnciContractInvoiceDO.builder()
                .id(updateDTO.getId())
                .upmNumber(updateDTO.getUpmNumber())
                .postingDate(updateDTO.getPostingDate())
                .updateUser(updateDTO.getUpdateUser())
                .updateTime(new Date())
                .build();
        this.baseMapper.updateById(cgnciContractInvoiceDO);
    }

    @Override
    public List<CgnciBusinessInsurancePageVO> queryBusiness() {
        List<String> businessType = new ArrayList<>();
        businessType.add("2");
        businessType.add("3");
        LambdaQueryWrapper<CgnciBusinessInsuranceDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(CgnciBusinessInsuranceDO::getBusinessType,businessType);
        queryWrapper.eq(CgnciBusinessInsuranceDO::getStatus, BusinessStatusEnum.COMPLETED.getCode());
        queryWrapper.eq(CgnciBusinessInsuranceDO::getIsMirror, "0");
        return ConvertUtils.convert(businessInsuranceMapper.selectList(queryWrapper),CgnciBusinessInsurancePageVO.class);
    }

    @Override
    public ReinsuranceVO queryReinsurer(Long insuranceId) {
        ReinsuranceVO reinsuranceVO = new ReinsuranceVO();
        // 分入信息
        reinsuranceVO.setDivideInVO(getDivideInReinsuranceByInsuranceId(insuranceId));
        // 临分分出信息
        reinsuranceVO.setCounterpartyVOList(listHyDivideOutReinsuranceByInsuranceId(insuranceId));
        return reinsuranceVO;
    }

    public List<CgnciCounterpartyVO> listHyDivideOutReinsuranceByInsuranceId(Long insuranceId) {
        List<CgnciCounterpartyVO> counterpartyVOS = new ArrayList<>();
        List<CgnciReinsuranceInfoDO> hydivideOutDOList = cgnciReinsuranceInfoMapper.selectList(new LambdaQueryWrapper<CgnciReinsuranceInfoDO>()
                .eq(CgnciReinsuranceInfoDO::getBusinessId, insuranceId)
                .eq(CgnciReinsuranceInfoDO::getReinsuranceType, 2));
        List<CgnciReinsuranceInfoVO> hyDivideOutVOList = ConvertUtils.convert(hydivideOutDOList, CgnciReinsuranceInfoVO.class);
        if (VerifyUtils.isNotEmpty(hyDivideOutVOList)) {
            hyDivideOutVOList.forEach(hyDivideOutVO -> {
                List<CgnciReinsuranceRiskDO> hyDivideOutRiskDOList = cgnciReinsuranceRiskService.list(new LambdaQueryWrapper<CgnciReinsuranceRiskDO>()
                        .eq(CgnciReinsuranceRiskDO::getReinsuranceId, hyDivideOutVO.getReinsuranceId()));
                List<CgnciReinsuranceRiskVO> hyDivideOutRiskRiskVOList = ConvertUtils.convert(hyDivideOutRiskDOList, CgnciReinsuranceRiskVO.class);
                if (VerifyUtils.isNotEmpty(hyDivideOutRiskRiskVOList)) {
                    // 分出险种
                    hyDivideOutRiskRiskVOList.forEach(risk -> {
                        List<CgnciReinsuranceRiskInsuredDO> insuredDOList = cgnciReinsuranceRiskInsuredService.list(new LambdaQueryWrapper<CgnciReinsuranceRiskInsuredDO>()
                                .eq(CgnciReinsuranceRiskInsuredDO::getReinsuranceRiskId, risk.getReinsuranceRiskId()));
                        if (VerifyUtils.isNotEmpty(insuredDOList)) {
                            List<CgnciReinsuranceRiskInsuredVO> insuredVOList = ConvertUtils.convert(insuredDOList, CgnciReinsuranceRiskInsuredVO.class);
                            insuredVOList.forEach(insuredVO -> {
                                List<CgnciReinsuranceRiskLayerDO> hyDivideOutRiskLayerDOList = cgnciReinsuranceRiskLayerService.list(new LambdaQueryWrapper<CgnciReinsuranceRiskLayerDO>()
                                        .eq(CgnciReinsuranceRiskLayerDO::getReinsuranceRiskId, insuredVO.getRiskInsuredId()));
                                if (VerifyUtils.isNotEmpty(hyDivideOutRiskLayerDOList)) {
                                    List<CgnciReinsuranceRiskLayerVO> hyDivideOutRiskLayerVOList = ConvertUtils.convert(hyDivideOutRiskLayerDOList, CgnciReinsuranceRiskLayerVO.class);
                                    hyDivideOutRiskLayerVOList.forEach(layer -> {
                                        // 查询交易对手
                                        List<CgnciReinsurerDO> reinsurerlist = reinsurerService.list(new LambdaQueryWrapper<CgnciReinsurerDO>()
                                                .eq(CgnciReinsurerDO::getReinsuranceId, layer.getLayerId()));
                                        // 使用LinkedHashSet保持插入顺序的同时去除重复
                                        counterpartyVOS.addAll(ConvertUtils.convert(reinsurerlist, CgnciCounterpartyVO.class));
                                    });
                                }
                            });
                        }
                    });
                }
            });
        }
        if(CollectionUtils.isEmpty(counterpartyVOS)){
            return counterpartyVOS;
        }
        Set<String> seenIds = new LinkedHashSet<>();
        // 如果添加成功（即以前未存在），则返回true并保留元素
        return counterpartyVOS.stream()
                .filter(e -> seenIds.add(e.getReinsurerCode())) // 如果添加成功（即以前未存在），则返回true并保留元素
                .collect(Collectors.toList());
    }

    private CgnciReinsuranceInfoVO getDivideInReinsuranceByInsuranceId(Long insuranceId) {
        CgnciReinsuranceInfoDO divideInDO = cgnciReinsuranceInfoMapper.selectOne(new LambdaQueryWrapper<CgnciReinsuranceInfoDO>()
                .eq(CgnciReinsuranceInfoDO::getBusinessId, insuranceId).eq(CgnciReinsuranceInfoDO::getReinsuranceType, 1));
        if (VerifyUtils.isNotEmpty(divideInDO)) {
            CgnciReinsuranceInfoVO divideInVO = ConvertUtils.convert(divideInDO, CgnciReinsuranceInfoVO.class);
            // 分入方案
            List<CgnciReinsurerVO> divideInReinsurerVOList = reinsurerService.listDivideInReinsurer(divideInDO.getReinsuranceId());
            // 使用LinkedHashSet保持插入顺序的同时去除重复
            if(VerifyUtils.isNotEmpty(divideInReinsurerVOList)) {
                Set<String> seenIds = new LinkedHashSet<>();
                divideInVO.setReinsurers(divideInReinsurerVOList.stream()
                        .filter(e -> seenIds.add(e.getReinsurerCode())) // 如果添加成功（即以前未存在），则返回true并保留元素
                        .collect(Collectors.toList()));
            }
            return divideInVO;
        }
        return null;
    }

    @Override
    public void delete(Long id,String invoiceNumber) {
       Integer count =  billsMapper.selectCount(new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                .eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber,invoiceNumber)
                .eq(CgnciReceiptPaymentBillsDO::getStatus,BillStatusEnum.UNSETTLED.getCode()));
       if(count==0){
           throw new GlobalException(ResponseCodeEnum.HTTP_REQUEST_SERVICE_ERROR, "收付费已关联，不允许删除");
       }
        this.baseMapper.deleteById(id);
        // 构建 LambdaQueryWrapper 并设置删除条件
        LambdaQueryWrapper<CgnciContractBillDetailsDO> wrapper = new LambdaQueryWrapper<CgnciContractBillDetailsDO>()
                .eq(CgnciContractBillDetailsDO::getInvoiceNumber, invoiceNumber);
        detailsMapper.delete(wrapper);
        //删除收付费管理数据
        billsMapper.delete(new LambdaQueryWrapper<CgnciReceiptPaymentBillsDO>()
                .eq(CgnciReceiptPaymentBillsDO::getInvoiceNumber,invoiceNumber));
    }
}
